///////////////////////////////////////////////////////////
// 
//  Horse.cpp
//
//  Wiicussion
//  HCI 575 Class project
//  Spring 2007
// 
//  Authors:  Jeremy Bennett
//            Adam Faeth
//            Michael Oren
//
///////////////////////////////////////////////////////////

//To Do: -Figure out how best to link myGame score to specific player...
//		 -Set things up in MyWindow so that the player's note gets passed in to checkIt and player score is set by checkIt's return value
//		 -Integrate w/ GlovePie -- note should be the MIDI note 0-127. MIDI channel should be set to 10 (percussion).


// Local Includes
#include "stdafx.h"
#include "Horse.h"
#include "Game.h"
#include "Player.h"
#include "MyContext.h"

#if defined(USE_MIDI_FUNCTIONS)
#include "PlayMidiLib.h"
#endif

// SDL Includes
#include <sdl.h>
#include <SDL_opengl.h>

// System Includes
#include <time.h>
#include <iostream>

//                                         | Mote 1    | Mote 2     |
const unsigned int s_uiMidiInstruments[] = { 48, 35, 42, 45, 38, 49 };


Horse::Horse(float fX, float fY, float fW, float fH, int playCount, int iInst, Player* curPlayers)
: Game(fX, fY, fW, fH),
  _seq(fX, fY + 500, fW, fH - 500, 1),
  _level(1),
  _curPos(0),
  _curPlayer(0),
  _playersLeft(playCount),
  _nPlayer(playCount),
  _myPlayers(curPlayers),
  _bPlaying()
{
	_notes.clear();

	for(int i=0; i<playCount; i++){
		_players.push_back(5);
		_myPlayers[i].resetScore();
		_myPlayers[i].setState(false);
	}
	_myPlayers[_curPlayer].toggleActive();
#if defined(USE_MIDI_FUNCTIONS)
	if(StartMidiOutForiDev(0)==MIDI_OUT_ERROR){
	   ("Couldn't open Midi Out - perhaps it is already in use for another application.\n\n"
		"Press return to exit."
	   );
	  getchar();
	  exit(0);
	 }
#endif
}

Horse::~Horse()
{
}

void Horse::addIt(int note)
{
	_notes.push_back(note);
	printf("Note added!\n");
}

bool Horse::checkIt(int note, bool matchedTime)
{
	if(_notes.size() == 0){
		addIt(note);
		do{
			_nextPlayer();
		}while(_players[_curPlayer] == 0);
		if(_level == 1){
			_seq.setTol(100);
			_seq.playback();
		}
		return true;
	}
	else if(_curPos > _notes.size()-1){
		addIt(note);
		do{
			_nextPlayer();
		}while(_players[_curPlayer] == 0);
		if(_level == 1)
			_seq.playback();
		return true;
	}

	if(_level==0){
		if(note == _notes[_curPos]){
			_curPos++;
			return true;
		}
		else{
			_players[_curPlayer]--;
			_myPlayers[_curPlayer].decrementScore();
			if(_players[_curPlayer] == 0){
				_playersLeft--;
				if(_playersLeft <= 1){
					gameOver();
                    return true;
				}
			}
            do{
				_nextPlayer();
			}while(_players[_curPlayer] == 0);
			_seq.playback();
			return false;
		}
	}
	else{
		if(note == _notes[_curPos] && matchedTime){
			_curPos++;
			return true;
		}
		else{
			_players[_curPlayer]--;
			_myPlayers[_curPlayer].decrementScore();
			if(_players[_curPlayer] == 0){
				_playersLeft--;
				if(_playersLeft <= 1){
					printf("Players left %d", _playersLeft);
					gameOver();
                    return true;
				}
			}
			do{
				_nextPlayer();
			}while(_players[_curPlayer] == 0);
			_seq.playback();
			return false;
		}
	}
}

void Horse::changeLevel(int newLevel)
{
	_level = newLevel;
}

void Horse::reset(int playCount)
{
	_notes.clear();
	_level = 1;
	_curPos = 0;
    _myPlayers[_curPlayer].toggleActive();
	_curPlayer = 1;
    _myPlayers[_curPlayer].toggleActive();
	_nPlayer = playCount;
	_playersLeft = _nPlayer;
	for(int i=0; i<playCount; i++){
		_players.push_back(5);
		_myPlayers[i].resetScore();
	}

}

// Handle events in the myGame
bool
Horse::handleEvents() 
{
    bool bRes = false;

    _updateState();
    
    if(_bActive) {
        SDL_Event   event;

		SDL_Joystick* pJoy = NULL; 
		bool bSustain=false;
		bool tMatched = false;
        
        // TOXIC:  This is a stub for testing sequences
        // Grab events from the queue
        while ( SDL_PollEvent(&event) ) {
            switch (event.type) {
                // Key Events:
				case SDL_JOYBUTTONDOWN:
				  printf("Joystick %d button %d down\n",event.jbutton.which,event.jbutton.button);
				  pJoy = SDL_JoystickOpen(event.jbutton.which);
				  #if defined(USE_MIDI_FUNCTIONS)
				  StopAllNotesPlayed(127);
				  #endif
				  for ( int x=0; x<_nPlayer; x++ ) {
					  if(x == _curPlayer){
#if defined(USE_GLOVEPIE)
						  if ( pJoy == _myPlayers[x].joystick()) {
							  //_myPlayers[x].toggleActive();
							  _myPlayers[x].setButton(int(event.jbutton.button),true);
							  int iDegree=-1;
							  int iDegree2 = -1;
							  for(int s = 4; s < 6; s++){
								  if(_myPlayers[x].getButton(s)){
									  switch(s){
										case 4: iDegree2 = 48; break;
										case 5: iDegree2 = 35; break;
										default: iDegree2 = 42;
									  }
								  }
							  }
							  if(iDegree2 == -1)
								  iDegree2 = 42;
							  _myPlayers[x].setInstrument(0, iDegree2-35);
							  if(_myPlayers[x].getButton(11)){
								  bool played = false;
								  for(int s = 4; s < 6; s++){
									  if(_myPlayers[x].getButton(s)){
										printf("%d\n",s);
										switch(s){
											case 4: iDegree = 48; played=true;
											  if(_notes.size() == 0 || _curPos > _notes.size() - 1)
												_seq.add(INST_BASE_HIGHMIDTOM, 0); 
											  else
												tMatched = _seq.match(INST_BASE_HIGHMIDTOM);
											  #if defined(USE_MIDI_FUNCTIONS)
											  if(iDegree>=0){
												PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
											  }
											  #endif
											  break;
											case 5: iDegree = 35; played=true;
											  if(_notes.size() == 0 || _curPos > _notes.size() - 1)
												_seq.add(INST_BASE_BASSDRUM, 0); 
											  else
												tMatched = _seq.match(INST_BASE_BASSDRUM); 
											  #if defined(USE_MIDI_FUNCTIONS)
											  if(iDegree>=0){
												PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
											  }
											  #endif
											  break;
										}
									  }
									 }
								  if(!played){
									  iDegree = 42;
									  
									  if(_notes.size() == 0 || _curPos > _notes.size() - 1)
										_seq.add(INST_BASE_HIHAT, 0); 
									  else
										tMatched = _seq.match(INST_BASE_HIHAT);
									  
									  #if defined(USE_MIDI_FUNCTIONS)
									  if(iDegree>=0){
										PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
									  }
									  #endif
								  }
								  //_myPlayers[x].setInstrument(iDegree-35);
							  }
							  if(iDegree>=0){
								//PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
								checkIt(iDegree, tMatched);
							  }
						  }
						  else if ( pJoy == _myPlayers[x].joystick2()) {
							  //_myPlayers[x].toggleActive();
							  _myPlayers[x].setButton2(int(event.jbutton.button),true);
							  int iDegree=-1;
							  int iDegree2 = -1;
							  for(int s = 4; s < 6; s++){
								  if(_myPlayers[x].getButton2(s)){
									  switch(s){
										case 4: iDegree2 = 45; break;
										case 5: iDegree2 = 38; break;
										default: iDegree2 = 49;
									  }
								  }
							  }
							  if(iDegree2 == -1)
								  iDegree2 = 49;
							  _myPlayers[x].setInstrument(1, iDegree2-35);
							  if(_myPlayers[x].getButton2(11)){
								  bool played = false;
								  for(int s = 4; s < 6; s++){
									  if(_myPlayers[x].getButton2(s)){
										  switch(s){
											case 4: iDegree = 45; played=true;
											  if(_notes.size() == 0 || _curPos > _notes.size() - 1)
												_seq.add(INST_BASE_LOWTOM, 0); 
											  else
												tMatched = _seq.match(INST_BASE_LOWTOM);
											  #if defined(USE_MIDI_FUNCTIONS)
											  if(iDegree>=0){
												PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
											  }
											  #endif
											  break;
											case 5: iDegree = 38; played=true;
											  if(_notes.size() == 0 || _curPos > _notes.size() - 1)
												_seq.add(INST_BASE_SNARE, 0); 
											  else
												tMatched = _seq.match(INST_BASE_SNARE);
											  #if defined(USE_MIDI_FUNCTIONS)
											  if(iDegree>=0){
												PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
											  }
											  #endif
											  break;
										}
									  }
									 }
								  if(!played){
									  iDegree = 49;
									  
									  if(_notes.size() == 0 || _curPos > _notes.size() - 1)
										_seq.add(INST_BASE_CRASHCYMBAL, 0); 
									  else
										tMatched = _seq.match(INST_BASE_CRASHCYMBAL);
									  
									  #if defined(USE_MIDI_FUNCTIONS)
									  if(iDegree>=0){
										PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
									  }
									  #endif
								  }
							  }
							  if(iDegree>=0){
								//PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+iDegree,127);
								checkIt(iDegree, tMatched);
							  }
						  }
#endif
					  }
				  }
				break;
				case SDL_JOYBUTTONUP:
				  //printf("Joystick %d button %d up\n",event.jbutton.which,event.jbutton.button);
				   pJoy = SDL_JoystickOpen(event.jbutton.which);
				   
				   #if defined(USE_MIDI_FUNCTIONS)
				   if( int(event.jbutton.button) == 11 && !bSustain)
					   StopAllNotesPlayed(127);
				   #endif

				   for ( int x=0; x<8; x++ ) {
#if defined(USE_GLOVEPIE)
		                if ( pJoy == _myPlayers[x].joystick()) {
                          //_myPlayers[x].toggleActive();
		                  _myPlayers[x].setButton(int(event.jbutton.button),false);
		                  int iDegree2 = -1;
		                  for(int s = 4; s < 6; s++){
			                  if(_myPlayers[x].getButton(s)){
				                  switch(s){
					                case 4: iDegree2 = 48; break;
					                case 5: iDegree2 = 35; break;
					                default: iDegree2 = 42;
				                  }
			                  }
		                  }
		                  if(iDegree2 == -1)
			                  iDegree2 = 42;
		                  _myPlayers[x].setInstrument(0, iDegree2-35);
		                }
		                if ( pJoy == _myPlayers[x].joystick2()) {
			                  //_myPlayers[x].toggleActive();
			                  _myPlayers[x].setButton2(int(event.jbutton.button),false);
			                  int iDegree2 = -1;
			                  for(int s = 4; s < 6; s++){
				                  if(_myPlayers[x].getButton2(s)){
					                  switch(s){
						                case 4: iDegree2 = 45; break;
						                case 5: iDegree2 = 38; break;
						                default: iDegree2 = 49;
					                  }
				                  }
			                  }
			                  if(iDegree2 == -1)
				                  iDegree2 = 49;
			                  _myPlayers[x].setInstrument(1, iDegree2-35);
		                }
#endif
				   }
				break;
                case SDL_KEYDOWN:
                    switch(event.key.keysym.sym) {
                        case SDLK_SPACE:
                            _seq.playback();
                            break;
                        // recording:
                        case SDLK_1:
                            _seq.add(INST_BASE_HIGHMIDTOM, 0);
                            break;
                        case SDLK_2:
                            _seq.add(INST_BASE_BASSDRUM, 0);
                            break;
                        case SDLK_3:
                            _seq.add(INST_BASE_HIHAT, 0);
                            break;
                        case SDLK_4:
                            _seq.add(INST_BASE_LOWTOM, 0);
                            break;
                        case SDLK_5:
                            _seq.add(INST_BASE_SNARE, 0);
                            break;
                        case SDLK_6:
                            _seq.add(INST_BASE_CRASHCYMBAL, 0);
                            break;
                        // playback:
                        case SDLK_F1:
                            _seq.match(INST_BASE_HIGHMIDTOM);
                            break;
                        case SDLK_F2:
                            _seq.match(INST_BASE_BASSDRUM);
                            break;
                        case SDLK_F3:
                            _seq.match(INST_BASE_HIHAT);
                            break;
                        case SDLK_F4:
                            _seq.match(INST_BASE_LOWTOM);
                            break;
                        case SDLK_F5:
                            _seq.match(INST_BASE_SNARE);
                            break;
                        case SDLK_F6:
                            _seq.match(INST_BASE_CRASHCYMBAL);
                            break;
                        case SDLK_g:
                            gameOver();
                            break;
                        case SDLK_y:
                            _nextPlayer();
                            break;
                        default:
                            break;
                    }
                    if ( event.key.keysym.sym != SDLK_ESCAPE ) {
                        break;  // Allow escape key to be used to quit
                    }
                case SDL_QUIT:
                    _bActive = false;
                    break;
                default:
                    break;
			}
		}
        bRes = true;
    }
    
    return bRes;
}

// Updates after rendering the frame
bool 
Horse::postFrame()
{
    return _seq.postFrame();
}

// Render method for the horse myGame

bool
Horse::renderGame( MyContext *pContext )
{
    _pContext = pContext; // TOXIC:  EEWWW HACKISH:

    glPushMatrix();
    glLoadIdentity();
    
    glTranslatef(_fRenderPos[0],_fRenderPos[1],0.0f);
    
    _seq.renderSequence(pContext);
    
    glPopMatrix();
        
    return true;
}

int 
Horse::getCurPlayer()
{
	return _curPlayer;
}

void 
Horse::gameOver()
{
	_bActive = false;
	_myPlayers[_curPlayer].toggleActive();
    _pContext->renderSplash(SPLASH_YOU_WIN, 1500, _fRenderSize[0]/2.0f, _fRenderSize[1]/2.0f, 512.0f, 256.0f);
	printf("GAME OVER!\n");
}

bool 
Horse::_updateState()
{
	if(_seq.hasPassed() && _players.size() > 0){
		_players[_curPlayer]--;
		_myPlayers[_curPlayer].decrementScore();
		if(_players[_curPlayer] == 0){
			_playersLeft--;
			if(_playersLeft <= 1){
				printf("Players left %d", _playersLeft);
				gameOver();
                return true;
			}
		}
		do{
			_nextPlayer();
		}while(_players[_curPlayer] == 0);
		_seq.playback();
	}

    Player* p = &_myPlayers[_curPlayer];
    
    if (p) {
        _updatePlaying(p,0); // Test Mote 1
        _updatePlaying(p,1); // Test Mote 2
    }

    return true;
}

bool 
Horse::_updatePlaying( Player* p, int iMote )
{
    bool bMatched = false;
    if ( p->isPlayingNote(iMote) ) {
        if ( _bPlaying[iMote] == false ) {
            int intsr = p->instrument(iMote);
            #if defined(USE_MIDI_FUNCTIONS)
            PlayNonMelodicPercussion(FIRST_GM_NON_MELOD_PERC+s_uiMidiInstruments[p->instrument(iMote)],127);
            #endif
            _bPlaying[iMote] = true;
            if(_notes.size() == 0 || _curPos > _notes.size() - 1) {
                _seq.add(intsr,0); 
            } else {
                bMatched = _seq.match(intsr);  
            }
            checkIt(s_uiMidiInstruments[intsr], bMatched);
        }
    } else {
        _bPlaying[iMote] = false;
        StopAllNotesPlayed(127);
    }

    return true;
}

bool 
Horse::_nextPlayer()
{
    _myPlayers[_curPlayer].toggleActive();
	_myPlayers[_curPlayer].setRumble(0,false);
	_myPlayers[_curPlayer].setRumble(1,false);
    _curPlayer++;
	if(_curPlayer >= _nPlayer)
		_curPlayer = 0;
	_curPos = 0;
    _myPlayers[_curPlayer].toggleActive();
	do{
		_pContext->renderSplash(SPLASH_NEXT_PLAYER, 50, _fRenderSize[0]/2.0f, _fRenderSize[1]/2.0f, 512.0f, 256.0f, false);
	}while(!_myPlayers[_curPlayer].isButtonPressed(0,WIIMOTE_BUTTON_A) && !_myPlayers[_curPlayer].isButtonPressed(1,WIIMOTE_BUTTON_A) && !_myPlayers[_curPlayer].isButtonPressed(0,WIIMOTE_BUTTON_B) && !_myPlayers[_curPlayer].isButtonPressed(1,WIIMOTE_BUTTON_B));
    return true;
}
